# Copyright (c) 2011, The merd Project
# All rights reserved.
   
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
#    * Neither the name of the merd project nor the names of its
#      contributors may be used to endorse or promote products derived
#      from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Pieter Hooimeijer, Dan Lepage

from time import sleep
from datetime import datetime
from inspect import getsource
from pysvn import Client, Revision, opt_revision_kind
from merd.data import DataSetBuilder
from merd.model import DataElt
from traceback import format_exc

client = Client()

def modified_revs(url, rev=Revision(opt_revision_kind.head)):
    """Get all revisions for the given URL. This is implemented
       as a chain of `log` calls in case a repository contains
       broken history chains for the same path"""

    if isinstance(rev, int):
        rev = Revision(opt_revision_kind.number, rev)
    
    try:
        while True:
            l = client.log(url, rev, limit=0)
            for x in l:
                r = x['revision']
                yield r
            rev = Revision(opt_revision_kind.number, r.number - 1)

    except Exception: # done
        return
    

src_default = "[Source code was not available]"
termination = "::Terminating at revision %s; traceback follows:\n%s"

rev_number = "rev_number"
rev_date   = "rev_date" 

class SingleFileSvnBuilder(DataSetBuilder):
    """SvnBuilder grabs the contents of a given SVN URL,
       constructing one data element for each SVN revision
       in a generator. URL is pegged at the head (i.e., 
       we assume the url points to a file that exists in
       the head revision). Sleeps a specified number of
       seconds between downloads."""
       
    def __init__(self, url, revgen, sleeptime=0):
        self.url = url
        self.revgen = revgen
        self.sleeptime = sleeptime

    def meta_description(self):
        src = src_default

        try:
            src = inspect.getsource(self.__class__)
        except Exception:
            pass

        return "Built with SvnBuilder\n====\n%s\n====\nSource:\n\n%s" \
            % (self.__doc__, src)

    def elt_gen(self):
        for rev in self.revgen:
            sleep(self.sleeptime)

            if isinstance(rev, int):
                rev = Revision(opt_revision_kind.number, rev)

            try:
                logentry = client.log(self.url, rev, limit = 1)[0]
                date = datetime.fromtimestamp(logentry["date"])
                name = "r%s" % (str(rev.number), )
                content  = client.cat(self.url, rev)
                
                retval = DataElt(name, content)
                retval.extradata = { rev_number : rev.number,
                                     rev_date   : date }

                yield retval
            except Exception:
                print termination % (rev.number, format_exc())
                return
